/*
 * 文件名：ParkwellCarOutServiceImpl.java	 
 * 时     间：下午7:36:18
 * 作     者：Administrator       
 * 版     权： 2012-2022 湖南智软网络科技, 公司保留所有权利.
 * 联     系：http://www.073586.com/
 */
package com.local.service.impl;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.lucene.index.IndexWriter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.druid.util.StringUtils;
import com.cloud.threads.UpDateCarOutInfoRunble;
import com.cloud.threads.UploadCarInInfoRunble;
import com.cloud.threads.UploadCarPayInfoRunble;
import com.cloud.threads.UploadPayBillRunble;
import com.cz073586.common.billRules.utils.DateUtil;
import com.cz073586.tools.util.Log4jUtil;
import com.cz073586.tools.util.ThreadPoolUtil;
import com.local.common.CommonContains;
import com.local.common.GateWayConstans;
import com.local.common.MessageContains;
import com.local.common.PayTypeConstans;
import com.local.dao.hismappers.CarParkInCopyMapper;
import com.local.dao.hismappers.CarParkOutCopyMapper;
import com.local.dao.hismappers.LocalPayBillMapper;
import com.local.dao.mapers.CarParkInMapper;
import com.local.dao.mapers.CarParkOutMapper;
import com.local.dao.mapers.LocalCarInRepertoryMapper;
import com.local.dao.mapers.LocalChargeBytimeCopyMapper;
import com.local.dao.mapers.LocalChargeBytimeMapper;
import com.local.dao.mapers.LocalEquipmentMapper;
import com.local.dao.mapers.LocalPayBillCopyMapper;
import com.local.dao.mapers.LocalPayBillRepeatMapper;
import com.local.dao.mapers.LocalScreenMapper;
import com.local.dao.mapers.ParklotNumberMapper;
import com.local.entity.vo.ParkwellPayBillVo;
import com.local.entity.vo.ScreenMessage;
import com.local.manager.cfgManager.CloudConfigManager;
import com.local.manager.cfgManager.ConfigManager;
import com.local.manager.locks.RepeatStaticEntity;
import com.local.manager.push.PushParkLotRunble;
import com.local.manager.thread.OpenCateThreadNew;
import com.local.manager.thread.UploadPlatformThread;
import com.local.model.AdminPayBill;
import com.local.model.CarLockInfo;
import com.local.model.CarParkIn;
import com.local.model.CarParkInCopy;
import com.local.model.CarParkOut;
import com.local.model.CarParkOutCopy;
import com.local.model.Crossing;
import com.local.model.Integration;
import com.local.model.LocalCarInRepertory;
import com.local.model.LocalCarInRepertoryExample;
import com.local.model.LocalChargeBytime;
import com.local.model.LocalChargeBytimeCopyExample;
import com.local.model.LocalChargeBytimeExample;
import com.local.model.LocalChargeBytimeType;
import com.local.model.LocalCoupon;
import com.local.model.LocalCouponCash;
import com.local.model.LocalEquipment;
import com.local.model.LocalEquipmentExample;
import com.local.model.LocalPayBill;
import com.local.model.LocalPayBillCopy;
import com.local.model.LocalPayBillCopyExample;
import com.local.model.LocalPayBillRepeat;
import com.local.model.LocalStation;
import com.local.model.Screen;
import com.local.service.face.AdminPayBillService;
import com.local.service.face.AutoOpenService;
import com.local.service.face.CarInAndOutService;
import com.local.service.face.CarLockInfoService;
import com.local.service.face.CrossingService;
import com.local.service.face.IntegrationService;
import com.local.service.face.LocalCouponCashService;
import com.local.service.face.LocalCouponService;
import com.local.service.face.LocalVersionService;
import com.local.service.face.LogService;
import com.local.service.face.ParkwellCarOutService;
import com.local.service.face.ParkwellChargeBytimeService;
import com.local.service.face.ParkwellPayBillService;
import com.local.util.MyDateUtil;
import com.qianhai.common.exception.BaseException;
import com.qianhai.common.utils.BeanUtil;
import com.qianhai.common.utils.Tools;
import com.qianhai.common.utils.UUIDGenerateUtil;
import com.zbc.lucene.util.FieldEnum;
import com.zbc.lucene.util.IndexUtil;
import com.zbc.lucene.util.LuceneConstants;

/**
 * 类描述:这里是类描述
 * 
 * @ClassName: ParkwellCarOutServiceImpl
 * @author Administrator
 * @date 2015年4月12日 下午7:36:18
 */
@Service
public class ParkwellCarOutServiceImpl implements ParkwellCarOutService
{
	
	private Log4jUtil log = Log4jUtil.getLog4j(ParkwellCarOutServiceImpl.class);
	
	@Autowired
	private LocalPayBillMapper parkwellPayBillMapper;
	
	@Autowired
	private LocalPayBillRepeatMapper localPayBillRepeatMapper;
	
	@Autowired
	private LocalChargeBytimeMapper localChargeBytimeMapper;
	
	@Autowired
	private LocalPayBillCopyMapper parkwellPayBillCopyMapper;
	
	@Autowired
	private ParkwellChargeBytimeService parkwellChargeBytimeService;
	
	@Autowired
	private CarParkInMapper carParkInMapper;
	
	@Autowired
	private CarParkOutMapper carParkOutMapper;
	
	@Autowired
	private LocalVersionService localVersionServiceImpl;
	
	@Autowired
	private CarInAndOutService carInAndOutService;
	
	@Autowired
	private LocalEquipmentMapper localEquipmentMapper;
	
	@Autowired
	private IntegrationService integrationService;
	
	@Autowired
	private CrossingService crossinService;
	
	@Autowired
	private ParkwellPayBillService paybillService;
	
	@Autowired
	private LogService logService;
	
	@Autowired
	private LocalCouponCashService localCouponCashService;
	
	@Autowired
	private LocalCouponService localCouponService;
	
	@Autowired
	private ParklotNumberMapper lotNumberMapper;
	
	@Autowired
	private AutoOpenService autoOpenService;
	
	@Autowired
	private CarLockInfoService carLockInfoService;
	@Autowired
	private AdminPayBillService adminPayBillService;
	
	@Autowired
	private CarParkOutCopyMapper carParkOutCopyMapper;
	
	@Autowired
	private CarParkInCopyMapper carParkInCopyMapper;
	
	@Autowired
	private LocalChargeBytimeCopyMapper chargeBytimeMapper;
	
	@Autowired
	private LocalPayBillCopyMapper localPayBillCopyMapper;
	
	@Autowired
	private LocalCarInRepertoryMapper localCarInRepertoryMapper;
	
	@Autowired
	private LocalScreenMapper localScreenMapper;
	
	@Override
	public ParkwellPayBillVo carOut(CarParkOut carParkOut,
			ParkwellPayBillVo parkwellPayBillVo)
	{
		try
		{
			if (parkwellPayBillVo.isNeedPrintPayBill())
			{
				carParkOut.setCarInUuid(parkwellPayBillVo.getCarInUuid());
			}
		} catch (Exception e)
		{
			parkwellPayBillVo.setError(true);
			parkwellPayBillVo.setErrorMsg(e.getMessage());
			log.error("", e);
			throw new BaseException(e.getMessage());
		}
		
		return parkwellPayBillVo;
	}
	
	// 更新进出场，记录状态
	public void updateCarInAndCarOut(ParkwellPayBillVo parkwellPayBillVo)
	{
		if (!Tools.isEmpty(parkwellPayBillVo.getCarInUuid()))
		{
			CarParkIn carInInfo = carParkInMapper
					.selectByPrimaryKey(parkwellPayBillVo.getCarInUuid());
			if (!Tools.isEmpty(carInInfo))
			{
				carInInfo.setStatus(0);
				carParkInMapper.updateByPrimaryKeySelective(carInInfo);
			}
		}
		if (!Tools.isEmpty(parkwellPayBillVo.getCarOutUuid()))
		{
			CarParkOut carParkOut = carParkOutMapper
					.selectByPrimaryKey(parkwellPayBillVo.getCarOutUuid());
			if (!Tools.isEmpty(carParkOut))
			{
				carParkOut.setCarInUuid(parkwellPayBillVo.getCarInUuid());
				carParkOut.setStatus(0);
				carParkOutMapper.updateByPrimaryKeySelective(carParkOut);
			}
		}
	}
	
	// 已有流水的总钱
	public Double queryPayBillByCarNo(String carNo)
	{
		// 6.查询车辆流水
		double countPrice = 0;
		List<LocalPayBill> payBillInfoList = paybillService
				.queryPayBillByCarNo(carNo);
		if (!Tools.isEmpty(payBillInfoList))
		{
			// 所有流水相加
			for (LocalPayBill bill : payBillInfoList)
			{
				countPrice += bill.getPrice();
			}
		}
		return countPrice;
	}
	
	/**
	 * 
	 * 方法描述： 计算本次进场车辆已经支付金额
	 * 
	 * @Title: calculateAreadyPayCount
	 * @param @param carInUUid
	 * @param @return
	 * @return double
	 * @user lyf 2015年11月6日
	 * @throws
	 */
	private double findCalculateAreadyPayCount(String carInUUid)
	{
		long startTime = System.currentTimeMillis();
		double countPrice = 0.0;
		List<LocalPayBillCopy> listbillList = parkwellPayBillCopyMapper
				.queryByCarInUuid(carInUUid);
		
		// 2016-04-05 更改为副本表
		/*
		 * LocalPayBillExample condition = new LocalPayBillExample();
		 * condition.or().andParkInUuidEqualTo(carInUUid); List<LocalPayBill>
		 * listbillList = parkwellPayBillMapper .selectByCondition(condition);
		 */
		log.debug("->查询入场入场所有流水:" + (System.currentTimeMillis() - startTime)
				+ "毫秒");
		if (!Tools.isEmpty(listbillList))
		{
			// 所有流水相加
			for (LocalPayBillCopy bill : listbillList)
			{
				countPrice += bill.getActualPrice();
			}
		}
		return countPrice;
	}
	
	public ParkwellPayBillVo loadparkwellPayBillVo(String carNo, Date inTime,
			String carInUuid, Date outTime, boolean falg)
	{
		ParkwellPayBillVo parkwellPayBillVo = new ParkwellPayBillVo();
		parkwellPayBillVo.setCarNo(carNo);
		parkwellPayBillVo.setCarInTime(inTime);
		parkwellPayBillVo.setCarInUuid(carInUuid);
		parkwellPayBillVo.setCarOutTime(outTime);
		parkwellPayBillVo.setParkTime((outTime.getTime() - inTime.getTime()));
		parkwellPayBillVo.setParkTimeString(MyDateUtil
				.periodToString(parkwellPayBillVo.getParkTime()));
		parkwellPayBillVo.setResult(falg);
		return parkwellPayBillVo;
	}
	
	/**
	 * 
	 * 方法描述：创建支付流水
	 * 
	 * @Title: createPayBill
	 * @param @param carNo
	 * @param @param parkUuid
	 * @param @param inTime
	 * @param @param happenTime
	 * @param @param carTypeUuid
	 * @param @param payType
	 * @return void
	 * @user Administrator 2015年4月12日
	 * @throws
	 */
	@Override
	public Double createPayBill(String carNo, Date inTime, Date happenTime,
			String carTypeUuid, String payType, String parkInUuid,
			Boolean isMember, Double priceDifference)
	{
		double price = 0.0;
		LocalPayBill parkwellPayBill = new LocalPayBill();
		parkwellPayBill.setCarNo(carNo);
		parkwellPayBill.setPayTime(new Date(System.currentTimeMillis()));
		parkwellPayBill.setPayType(payType);
		if (!Tools.isEmpty(priceDifference))
		{
			parkwellPayBill.setPrice(priceDifference);
		} else
		{
			// price = queryCalculatePrice(inTime, happenTime, carTypeUuid);
			parkwellPayBill.setPrice(price);
		}
		if (isMember)
		{
			parkwellPayBill.setActualPrice(0d);
		}
		parkwellPayBill.setParkInUuid(parkInUuid);
		parkwellPayBill.setPayBillUuid(UUIDGenerateUtil.generate());
		parkwellPayBill
				.setVersion(localVersionServiceImpl
						.selectLocalVersionByVersionType(CommonContains.VERSION_PAY_BILL));
		parkwellPayBillMapper.insert(parkwellPayBill);
		if (CloudConfigManager.instance().isOpen())
		{
			UploadPayBillRunble upload = new UploadPayBillRunble(
					parkwellPayBill, logService);
			ThreadPoolUtil.instance().execute(upload);
		}
		
		return price;
	}
	
	/**
	 * 
	 * 方法描述：调用支付接口,并计算出具体金额
	 * 
	 * @Title: calculatePrice
	 * @param @param parkUuid
	 * @param @param happenTime
	 * @param @param parkwellMemberCard
	 * @param @return
	 * @return Double
	 * @user Administrator 2015年4月12日
	 * @throws
	 */
	public Double queryCalculatePrice(Date inTime, Date happenTime,
			String carTypeUuid, ParkwellPayBillVo parkwellPayBillVo)
	{
		Double price = 0d;
		try
		{
			LocalChargeBytime chargeBytime = new LocalChargeBytime();
			chargeBytime.setInTime(inTime);
			chargeBytime.setOutTime(happenTime);
			chargeBytime.setCarType(carTypeUuid);
			price = parkwellChargeBytimeService.queryBilling(chargeBytime,
					parkwellPayBillVo);
		} catch (BaseException e)
		{
		}
		return price;
	}
	
	/**
	 * 
	 * 方法描述：计算车牌电子代金券总价，上传电子代金券列表，并且删除
	 * 
	 * @Title: calculatePrice
	 * @param @param parkUuid
	 * @param @param happenTime
	 * @param @param parkwellMemberCard
	 * @param @return
	 * @return Double
	 * @user Administrator 2015年4月12日
	 * @throws
	 */
	private Double calculateCouponPrice(String carNo, String carInUuid,
			Date carInTime, Double price, ParkwellPayBillVo parkwellPayBillVo)
	{
		List<LocalCouponCash> li = localCouponCashService
				.queryCouponCashByCarNo(carNo);
		// CarParkIn carInfo = carParkInMapper.selectByPrimaryKey(carInUuid);
		double money = 0.0;
		if (!Tools.isEmpty(li) && price > 0)
		{
			for (LocalCouponCash lc : li)
			{
				LocalPayBillCopy parkwellPayBill = new LocalPayBillCopy();
				parkwellPayBill.setPayBillUuid(UUIDGenerateUtil.generate());
				parkwellPayBill.setCarNo(carNo);
				parkwellPayBill
						.setPayTime(new Date(System.currentTimeMillis()));
				parkwellPayBill.setPayType(!Tools.isEmpty(lc.getArrtr1()) ? lc
						.getArrtr1() : "抵用劵");
				parkwellPayBill.setPrice(!Tools.isEmpty(lc.getPrice()
						.doubleValue()) ? lc.getPrice().doubleValue() : 0);
				parkwellPayBill.setActualPrice(!Tools.isEmpty(lc.getPrice()
						.doubleValue()) ? lc.getPrice().doubleValue() : 0);
				parkwellPayBill.setParkInUuid(carInUuid);
				parkwellPayBill
						.setVersion(localVersionServiceImpl
								.selectLocalVersionByVersionType(CommonContains.VERSION_PAY_BILL));
				parkwellPayBill.setCarinCreatAt(carInTime);
				parkwellPayBillCopyMapper.insertSelective(parkwellPayBill);
				
				LocalPayBill pc = new LocalPayBill();
				BeanUtil.copyProperties(pc, parkwellPayBill);
				
				/*
				 * // 抵用劵，转换为流水，并且上传 if (CloudConfigManager.instance().isOpen())
				 * { UploadPayBillRunble upload = new UploadPayBillRunble(pc,
				 * logService); ThreadPoolUtil.instance().execute(upload); }
				 */
				parkwellPayBillVo.getLscList().add(lc);
				money += lc.getPrice();
				// 删除本地系统的，商家抵用劵情况
				localCouponCashService.deleteByPrimaryKey(lc.getCouponId());
				/*
				 * if (money >= price) { return money; }
				 */
			}
		}
		return money;
	}
	
	/**
	 * 
	 * 方法描述： 通过设备编号获取
	 * 
	 * @Title: queryEquipMentByCameraNo
	 * @param @param cameNo
	 * @param @return
	 * @return LocalEquipment
	 * @user Administrator 2015年10月1日
	 * @throws
	 */
	@Override
	public LocalEquipment queryEquipMentByCameraNo(String cameNo)
	{
		LocalEquipmentExample ex = new LocalEquipmentExample();
		ex.or().andCameraNoEqualTo(cameNo);
		List<LocalEquipment> list = localEquipmentMapper.selectByCondition(ex);
		return list.isEmpty() ? null : list.get(0);
	}
	
	public boolean returnIntegration(ParkwellPayBillVo parkwellPayBillVo)
	{
		Integration ingra = integrationService
				.queryInterationByCarNo(parkwellPayBillVo.getCarNo());
		if (Tools.isEmpty(ingra))
		{
			return false;
		}
		if (ingra.getFromPark().equals("1"))
		{
			if (ingra.getLessPrice()
					- (parkwellPayBillVo.getTheoryPriceDb() - parkwellPayBillVo
							.getAreadyPayPrice()) > 0)
			{
				if (CloudConfigManager.instance().isOpen())
				{
					UploadCarPayInfoRunble upload = new UploadCarPayInfoRunble(
							parkwellPayBillVo);
					ThreadPoolUtil.instance().execute(upload);
					return true;
				}
			}
		}
		return false;
	}
	
	@SuppressWarnings("static-access")
	@Override
	public ParkwellPayBillVo queryGenerateVirtualBill(CarParkOut carParkOut,
			ParkwellPayBillVo parkwellPayBillVo) throws BaseException
	{
		try
		{
			long startTime = System.currentTimeMillis();
			carParkOut.setOriginalCarNo(carParkOut.getCarNo());
			
			// 1.进场非空验证
			if (Tools.isEmpty(carParkOut.getCarNo()))
			{
				carParkOut.setCarNo("无效车牌");
			}
			
			if (Tools.isEmpty(carParkOut.getExchangeUuid()))
			{
				throw new BaseException("15000-00000-00015");
			}
			
			// 判断相机传送过来的数据是否有路口信息，防止伪数据
			startTime = System.currentTimeMillis();
			List<Crossing> crossList = crossinService
					.queryCrossingByEquimentNo(carParkOut.getEquipment());
			log.debug("查询路口信息:" + (System.currentTimeMillis() - startTime)
					+ "毫秒");
			if (Tools.isEmpty(crossList) || crossList.isEmpty())
			{
				throw new BaseException("50000-00001-00046");
			}
			// 设置路口信息
			if (crossList.size() > 0)
			{
				parkwellPayBillVo.setRoadNmae(crossList.get(0).getName());
				parkwellPayBillVo.setRoadUuid(crossList.get(0).getUuid());
				// 检查控制汇总开关 2016-71-24
				if (!Tools.isEmpty(crossList.get(0).getProcessId()))
				{
					parkwellPayBillVo.setCollect(true);
					parkwellPayBillVo.setCollectRoadUuid(crossList.get(0)
							.getProcessId());
					parkwellPayBillVo.setCollectCtrEqNo(crossList.get(0)
							.getEquipmentViewStream());
				}
				// 检查控制汇总开关 2016-71-24
			}
			
			// 初始化Led屏幕显示信息
			ScreenMessage screenMessage = new ScreenMessage();
			// 检查控制汇总开关 2016-71-24
			String equimentNo = carParkOut.getEquipment();
			if (parkwellPayBillVo.isCollect())
			{
				// 主控相机编码
				equimentNo = parkwellPayBillVo.getCollectCtrEqNo();
			}
			// 检查控制汇总开关 2016-71-24
			Screen screen = localScreenMapper
					.queryScreenByCamelDeviceId(equimentNo);
			parkwellPayBillVo.setScreen(screen);
			
			// 云锁车信息
			if (ConfigManager.instance().isLockFlag())
			{
				// 车辆被锁,所有情况都不能出场
				CarLockInfo carLockInfo = carLockInfoService.queryFindByCarNo(
						parkwellPayBillVo.getCarNo(),
						carParkOut.getExchangeUuid());
				log.debug("查询车辆是否加锁:"
						+ (System.currentTimeMillis() - startTime) + "毫秒");
				// 1已加锁， 0 已解锁
				if (!Tools.isEmpty(carLockInfo)
						&& !Tools.isEmpty(carLockInfo.getCarLock())
						&& carLockInfo.getCarLock() == 1)
				{
					parkwellPayBillVo.setResult(false);
					screenMessage.setHeadMsg(parkwellPayBillVo.getCarNo());
					screenMessage.setThirdMsg(MessageContains.LOCK_MSG);
					parkwellPayBillVo.setScreenMsg(screenMessage);
					return parkwellPayBillVo;
				}
			}
			
			// 初始化状态值
			// 状态:未出(1) 已出 0
			parkwellPayBillVo.setUuid(carParkOut.getUuid());
			// 设置出场时间
			parkwellPayBillVo.setCarOutTime(carParkOut.getCreateTime());
			parkwellPayBillVo.setCarNo(carParkOut.getCarNo());
			parkwellPayBillVo.setCarOutUuid(carParkOut.getUuid());
			parkwellPayBillVo.setCarInUuid(!Tools.isEmpty(carParkOut
					.getCarInUuid()) ? carParkOut.getCarInUuid() : null);
			parkwellPayBillVo.setCarNoTye("临时车");
			parkwellPayBillVo.setBillType("102");
			parkwellPayBillVo.setCarTypeUuid(ConfigManager.instance()
					.getDefaultCarType());
			
			// 执行抓拍，相机调用此方法直接不开闸弹框，没有进场记录
			if (Tools.isEmpty(parkwellPayBillVo.getCarInUuid())
					&& "无效车牌".equalsIgnoreCase(carParkOut.getCarNo()))
			{
				parkwellPayBillVo.setResult(false);
				return parkwellPayBillVo;
				// return 要求用户输入车牌号、或输入车牌信息
			}
			
			// 查找出场结果记录，1.相机直接识别只有车牌号通过车牌号找 2.用户查找进场记录
			LocalCarInRepertory carInRepertory = null;
			
			// 保安执行查找进场记录时，通过匹配车记录
			if (!Tools.isEmpty(parkwellPayBillVo.getCarInUuid()))
			{
				carInRepertory = localCarInRepertoryMapper
						.queryCarInRepertoryByCarInUuid(parkwellPayBillVo
								.getCarInUuid());
			}
			
			// 相机识别通过车牌查找
			if (Tools.isEmpty(carInRepertory))
			{
				carInRepertory = localCarInRepertoryMapper
						.queryCarInRepertoryByCarNo(!Tools.isEmpty(carParkOut
								.getCarNo()) ? carParkOut.getCarNo()
								: parkwellPayBillVo.getCarNo());
			}
			
			// 判断是否打开控制开关，跳过计费
			// 2016-1-18 判断是否启用出场开闸标记,如果开启自动开闸,更新出场纪录为出场、无需计费
			boolean isAutoOpen = autoOpenService.getCurrentSwitch();
			log.debug("判断是否启用出场开闸标记:"
					+ (System.currentTimeMillis() - startTime) + "毫秒");
			if (isAutoOpen)
			{
				
				// 全局统一查询车牌类型,//是否会员，免费车，警车，军车,黄牌色，蓝牌色，单排车等....
				CarParkIn carI = new CarParkIn();
				carI.setCarNo(!Tools.isEmpty(carParkOut.getCarNo()) ? carParkOut
						.getCarNo() : parkwellPayBillVo.getCarNo());
				carI.setBrand(!Tools.isEmpty(carParkOut.getBrand()) ? carParkOut
						.getBrand() : "102");
				LocalChargeBytimeType ltc = carInAndOutService
						.makeCarNoType(carI);
				String carNoType = !Tools.isEmpty(ltc) ? ltc.getName()
						: MessageContains.TEMP_CAR_TYPE;
				carParkOut.setAttr1(carNoType);
				carParkOut
						.setBrand(!Tools.isEmpty(ltc) ? ltc.getType() : "102");
				
				if (!Tools.isEmpty(ltc))
				{
					parkwellPayBillVo.setCarNoTye(ltc.getName());
					carParkOut.setBrand(ltc.getType());
				}
				
				startTime = System.currentTimeMillis();
				parkwellPayBillVo.setResult(true);
				parkwellPayBillVo.setCarOutUuid(carParkOut.getUuid());
				CarParkIn carParkIn = carParkInMapper.selectCarNo(carParkOut
						.getCarNo());
				if (!Tools.isEmpty(carParkIn))
				{
					// 状态:未出(1) 已出 0
					parkwellPayBillVo.setCarInTime(carParkIn.getCreateTime());
					// 设置出场时间
					parkwellPayBillVo.setCarOutTime(carParkOut.getCreateTime());
					parkwellPayBillVo.setCarNo(carParkOut.getCarNo());
					parkwellPayBillVo.setCarOutUuid(carParkOut.getUuid());
					parkwellPayBillVo.setCarInUuid(carParkIn.getUuid());
				}
				
				/* updateCarInAndCarOut(parkwellPayBillVo); */
				log.debug("自动开闸:" + (System.currentTimeMillis() - startTime)
						+ "毫秒");
				screenMessage.setHeadMsg(parkwellPayBillVo.getCarNo());
				screenMessage.setThirdMsg(MessageContains.GOOD_BYE_MSG);
				parkwellPayBillVo.setScreenMsg(screenMessage);
				return parkwellPayBillVo;
			}
			
			// 计费规则主键
			LocalChargeBytime localChargeBytime = null;
			
			// 共享收费类型
			LocalChargeBytimeType ltc = null;
			
			// 初始化计费规则,无中间表就通过车牌类型确定计费规则
			if (Tools.isEmpty(carInRepertory))
			{
				// 全局统一查询车牌类型,//是否会员，免费车，警车，军车,黄牌色，蓝牌色，单排车等....
				CarParkIn carI = new CarParkIn();
				carI.setCarNo(!Tools.isEmpty(carParkOut.getCarNo()) ? carParkOut
						.getCarNo() : parkwellPayBillVo.getCarNo());
				carI.setBrand(!Tools.isEmpty(carParkOut.getBrand()) ? carParkOut
						.getBrand() : "102");
				ltc = carInAndOutService.makeCarNoType(carI);
				String carNoType = !Tools.isEmpty(ltc) ? ltc.getName()
						: MessageContains.TEMP_CAR_TYPE;
				carParkOut.setAttr1(carNoType);
				carParkOut
						.setBrand(!Tools.isEmpty(ltc) ? ltc.getType() : "102");
				
				// 获取计费规则类型 type
				String type = "102";
				if (!Tools.isEmpty(ltc))
				{
					type = ltc.getType();
					parkwellPayBillVo.setCarNoTye(ltc.getName());
					carParkOut.setBrand(ltc.getType());
					parkwellPayBillVo.setBillType(!Tools.isEmpty(ltc) ? ltc
							.getType() : "102");
				}
				// 获取计费规则
				LocalChargeBytimeExample chagertion = new LocalChargeBytimeExample();
				chagertion.or().andAttr4EqualTo(type);
				List<LocalChargeBytime> chargeList = localChargeBytimeMapper
						.selectByCondition(chagertion);
				localChargeBytime = !Tools.isEmpty(chargeList)
						&& chargeList.size() > 0 ? chargeList.get(0) : null;
				
				// 没有进场纪录，则直接开闸
				if (!Tools.isEmpty(localChargeBytime)
						&& "0".equalsIgnoreCase(localChargeBytime
								.getBaseTimeCharge())
						&& "0".equalsIgnoreCase(localChargeBytime
								.getAccountTimeCharge())
						&& "0".equalsIgnoreCase(localChargeBytime.getAttr2()))
				{
					carParkOut.setAttr1(parkwellPayBillVo.getCarNoTye());
					carParkOut.setCarType(ConfigManager.instance()
							.getDefaultCarType());
					// 开闸
					screenMessage.setHeadMsg(parkwellPayBillVo.getCarNo());
					// screenMessage.setSecMsg(ltc.getName());
					screenMessage.setThirdMsg(MessageContains.GOOD_BYE_MSG);
					parkwellPayBillVo.setScreenMsg(screenMessage);
					
					parkwellPayBillVo.setResult(true);
					return parkwellPayBillVo;
				}
				
				// 临时车，没有进场纪录，直接不开闸弹框,找进场纪录
				parkwellPayBillVo.setCarNoTye(ltc.getName());
				parkwellPayBillVo.setResult(false);
				screenMessage.setHeadMsg(parkwellPayBillVo.getCarNo());
				screenMessage.setSecMsg(ltc.getName());
				screenMessage.setFootMsg(MessageContains.WAIT_PAY_MSG);
				parkwellPayBillVo.setScreenMsg(screenMessage);
				return parkwellPayBillVo;
			}
			
			// 有进场纪录，放入进场时间
			parkwellPayBillVo.setRepertoryUuid(carInRepertory.getUuid());// 2016-6-1
																			// 防止无法删除该表
			parkwellPayBillVo.setCarInTime(carInRepertory.getCarInTime());
			parkwellPayBillVo.setCarTypeUuid(carInRepertory.getCarTypeUuid());
			parkwellPayBillVo.setParkTime((parkwellPayBillVo.getCarOutTime()
					.getTime() - parkwellPayBillVo.getCarInTime().getTime()));
			parkwellPayBillVo.setParkTimeString(MyDateUtil
					.periodToString(parkwellPayBillVo.getParkTime()));
			parkwellPayBillVo.setCarInUuid(!Tools.isEmpty(parkwellPayBillVo
					.getCarInUuid()) ? parkwellPayBillVo.getCarInUuid()
					: carInRepertory.getCarInUuid());
			
			// 有进场通过进场中间表返回类型
			if (!Tools.isEmpty(carInRepertory)
					&& Tools.isEmpty(carInRepertory.getChargeUuid()))
			{
				LocalChargeBytimeExample condtion = new LocalChargeBytimeExample();
				condtion.or().andAttr4EqualTo("102");
				localChargeBytime = localChargeBytimeMapper.selectByCondition(
						condtion).get(0);
				carInRepertory.setChargeUuid(localChargeBytime
						.getChargeBytimeUuid());
				ltc = carInAndOutService.getFirCarTypeNo("102");
				carParkOut.setBrand(ltc.getType());
				parkwellPayBillVo.setBillType(!Tools.isEmpty(ltc) ? ltc
						.getType() : "102");
			}
			
			// 初始化计费规则类型
			if (!Tools.isEmpty(carInRepertory))
			{
				if (Tools.isEmpty(carInRepertory.getAttr()))
				{
					CarParkIn carI = new CarParkIn();
					carI.setCarNo(!Tools.isEmpty(carInRepertory.getCarNo()) ? carInRepertory
							.getCarNo() : parkwellPayBillVo.getCarNo());
					carI.setBrand(!Tools.isEmpty(carParkOut.getBrand()) ? carParkOut
							.getBrand() : "102");
					ltc = carInAndOutService.makeCarNoType(carI);
				} else
				{
					ltc = carInAndOutService.getFirCarTypeNo(carInRepertory
							.getAttr());
				}
				
				carParkOut.setBrand(ltc.getType());
				parkwellPayBillVo.setBillType(!Tools.isEmpty(ltc) ? ltc
						.getType() : "102");
			}
			
			// 设置车牌类型
			parkwellPayBillVo.setCarNoTye(!Tools.isEmpty(ltc) ? ltc.getName()
					: parkwellPayBillVo.getCarNoTye());
			// 设置会员车、免费车
			if (!parkwellPayBillVo.getCarNoTye().equals("102"))
			{
				screenMessage.setSecMsg(parkwellPayBillVo.getCarNoTye());
			}
			// 开始计费
			String chargeUuid = Tools.isEmpty(carInRepertory) ? localChargeBytime
					.getChargeBytimeUuid() : carInRepertory.getChargeUuid();
			
			// 如果 carInRepertory 有超期时间，则为特殊车辆.
			if (!Tools.isEmpty(carInRepertory)
					&& !Tools.isEmpty(carInRepertory.getExpireTime()))
			{
				// 如果超期转变计费规则为临时计费规则
				long exDate = carInRepertory.getExpireTime().getTime()
						- System.currentTimeMillis();
				if (exDate <= 0)
				{
					// 进场时间大于过期时间，按进场时间算。进场小于超期时间，按照超期时间。
					long carInTime = carInRepertory.getCarInTime().getTime();
					long exprireTime = carInRepertory.getExpireTime().getTime();
					if (carInTime > exprireTime)
					{
						parkwellPayBillVo.setCarInTime(carInRepertory
								.getCarInTime());
					} else
					{
						parkwellPayBillVo.setCarInTime(carInRepertory
								.getExpireTime());
					}
					LocalChargeBytimeExample condtion = new LocalChargeBytimeExample();
					condtion.or().andAttr4EqualTo("102");
					localChargeBytime = localChargeBytimeMapper
							.selectByCondition(condtion).get(0);
					ltc = carInAndOutService.getFirCarTypeNo("102");
					parkwellPayBillVo.setCarNoTye(ltc.getName());
					parkwellPayBillVo.setBillType(!Tools.isEmpty(ltc) ? ltc
							.getType() : "102");
					carParkOut.setBrand(ltc.getType());
					chargeUuid = localChargeBytime.getChargeBytimeUuid();
				}
				
				// 屏幕还剩多少天
				if (exDate >= 0)
				{
					screenMessage.setFootMsg(MessageFormat.format(
							MessageContains.FOOT_MSG,
							(carInRepertory.getExpireTime().getTime() - System
									.currentTimeMillis())
									/ CommonContains.ONE_DAY_SEC));
				}
			}
			
			Double price = parkwellChargeBytimeService.queryCarinBillMoney(
					chargeUuid, parkwellPayBillVo.getCarInTime(),
					parkwellPayBillVo.getCarOutTime());
			
			parkwellPayBillVo.setTheoryPriceDb(price);
			
			/**
			 * 封装出场
			 */
			if (!Tools.isEmpty(price) && price <= 0)
			{
				// 统一分装流水数据结构
				encapsulationPayBill(parkwellPayBillVo, carParkOut, ltc,
						screenMessage);
				return parkwellPayBillVo;
			}
			
			// true关闭了滚动计费 false:开启了滚动计费
			Boolean repeat = RepeatStaticEntity.instance()
					.getRepeatStaticLock();
			
			// false表示开启了滚动计费(有计费规则、启用一天封顶)
			if (!repeat && Tools.isEmpty(localChargeBytime))
			{
				// 获取当前计费规则的 最大封顶费用
				localChargeBytime = localChargeBytimeMapper
						.selectByPrimaryKey(chargeUuid);
			}
			
			if (!repeat && !Tools.isEmpty(localChargeBytime)
					&& !Tools.isEmpty(localChargeBytime.getAttr2()))
			{
				
				// 一天封顶价格
				double capping = Double.parseDouble(localChargeBytime
						.getAttr2());
				
				// 查询滚动计费流水表（今天共支出多少钱）
				Double payRepeat = paybillService
						.countCarNoRepeatMoney(parkwellPayBillVo.getCarNo());
				
				// 查询非今天计费流水(上次停车交的钱)
				Double historyPrice = paybillService
						.countCarNoNext(parkwellPayBillVo.getCarNo());
				
				// 非跨天
				if (price <= capping && (price + payRepeat) > capping)
				{
					price = capping - payRepeat;
					
				}
				
				// 跨天
				if (price >= capping)
				{
					price = price - payRepeat - historyPrice;
				}
				
				if (price <= 0)
				{
					// 统一分装流水数据结构
					encapsulationPayBill(parkwellPayBillVo, carParkOut, ltc,
							screenMessage);
					return parkwellPayBillVo;
				}
				
			}// end 滚动计费
			
			// 已支付的总钱
			startTime = System.currentTimeMillis();
			Double areadyPayPrice = findCalculateAreadyPayCount(carInRepertory
					.getCarInUuid());
			log.debug("查询已支付费用:" + (System.currentTimeMillis() - startTime)
					+ "毫秒");
			// 默认使用抵用劵，生成流水
			double couponCashPrice = calculateCouponPrice(
					carInRepertory.getCarNo(), carInRepertory.getCarInUuid(),
					carInRepertory.getCarInTime(), price - areadyPayPrice,
					parkwellPayBillVo);
			
			// 赋值----商家抵用劵
			// 赋值----电子代金卷(暂无)
			returnCashOrVouchers(parkwellPayBillVo,
					carInRepertory.getCarInUuid());
			
			parkwellPayBillVo
					.setCouponCashPrice(!Tools.isEmpty(parkwellPayBillVo
							.getCouponCashPrice()) ? parkwellPayBillVo
							.getCouponCashPrice() : couponCashPrice);
			parkwellPayBillVo.setCouponVouchers(0d);
			
			// 已支付的总钱
			areadyPayPrice = findCalculateAreadyPayCount(carInRepertory
					.getCarInUuid());
			
			parkwellPayBillVo.setAreadyPayPrice(areadyPayPrice);
			
			// 查询集成表
			startTime = System.currentTimeMillis();
			if (ConfigManager.instance().isCloudPay())
			{
				Integration ingra = integrationService
						.queryInterationByCarNo(parkwellPayBillVo.getCarNo());
				log.debug("查询集成表:" + (System.currentTimeMillis() - startTime)
						+ "毫秒");
				// 如果存在,是平台用户
				if (!Tools.isEmpty(ingra))
				{
					if (!Tools.isEmpty(ingra.getAttr1())
							&& ingra.getAttr1().equalsIgnoreCase("1"))
					{
						// 并且当前支付金额不满足出场
						if (ingra.getFromPark().equals("1")
								&& price - areadyPayPrice > 0)
						{
							// 百事通账户，自动扣费
							if (ingra.getLessPrice() - (price - areadyPayPrice) > 0)
							{
								parkwellPayBillVo.setAuotPayOut(true);
								parkwellPayBillVo.setResult(true);
								parkwellPayBillVo.setNeedPrintPayBill(true);
								parkwellPayBillVo.setPayType("自动扣费");
								parkwellPayBillVo.setPriceDifference(price
										- areadyPayPrice);
								screenMessage.setHeadMsg(parkwellPayBillVo
										.getCarNo());
								screenMessage.setSecMsg(ltc.getName());
								screenMessage
										.setThirdMsg(MessageContains.GOOD_BYE_MSG);
								screenMessage.setFootMsg(MessageFormat.format(
										MessageContains.FOOT_AUTO_PAY_MSG,
										price));
								parkwellPayBillVo.setScreenMsg(screenMessage);
								return parkwellPayBillVo;
							}
						}
					}
				}
			}
			
			if (areadyPayPrice < price) // 补差价
			{
				BigDecimal bd1 = new BigDecimal(Double.toString(price));
				BigDecimal bd2 = new BigDecimal(Double.toString(areadyPayPrice));
				parkwellPayBillVo.setPriceDifference(bd1.subtract(bd2)
						.doubleValue());
				parkwellPayBillVo.setResult(false);
				screenMessage.setSecMsg(ltc.getName());
				/*
				 * screenMessage.setSecMsg(MessageFormat.format(
				 * MessageContains.FOOT_AUTO_PAY_MSG, areadyPayPrice));
				 */
				screenMessage.setHeadMsg(parkwellPayBillVo.getCarNo());
				screenMessage.setFootMsg(MessageFormat.format(
						MessageContains.FOOT_PAY_MSG,
						parkwellPayBillVo.getPriceDifference()));
				parkwellPayBillVo.setScreenMsg(screenMessage);
				// throw new BaseException("15000-00000-00018");
				return parkwellPayBillVo;
			}
			
			// 2015-11-20，如果流水已经够本初出场，则无车辆开出时无需再打印流水
			if (!Tools.isEmpty(areadyPayPrice) && areadyPayPrice != 0)
			{
				parkwellPayBillVo.setNeedPrintPayBill(false);
			}
			carParkOut.setAttr1(parkwellPayBillVo.getCarNoTye());
			carParkOut.setType(ConfigManager.instance().getDefaultCarType());
			parkwellPayBillVo.setResult(true);
			screenMessage.setHeadMsg(parkwellPayBillVo.getCarNo());
			screenMessage.setSecMsg(ltc.getName());
			screenMessage.setThirdMsg(MessageContains.GOOD_BYE_MSG);
			parkwellPayBillVo.setScreenMsg(screenMessage);
			
			// 判断车两类型，设置不同值
			if (ltc.getType().equals("102") && parkwellPayBillVo.isResult()) // 临时车
			{
				// 一路顺风
				screenMessage.setThirdMsg(MessageContains.GOOD_BYE_MSG);
			}
			
			return parkwellPayBillVo;
		} catch (Throwable e)
		{
			parkwellPayBillVo.setResult(true);// 报错默认开闸
			log.error("计费方法异常-" + Thread.currentThread().getId(), e);
			throw new BaseException(e.getMessage());
		} finally
		{
			// 检查控制汇总开关 2016-71-24
			if (parkwellPayBillVo.isCollect() && parkwellPayBillVo.isResult())
			{
				// 汇总开闸
				OpenCateThreadNew openCateRunble = new OpenCateThreadNew(
						crossinService, parkwellPayBillVo.getCollectRoadUuid());
				ThreadPoolUtil.instance().execute(openCateRunble);
			}
			// 检查控制汇总开关 2016-71-24
			
			// 设置没开闸标记
			if (!parkwellPayBillVo.isResult())
			{
				carParkOut.setOpenMode(GateWayConstans.UNOPENED);
			}
		}
	}
	
	@Override
	public Integer createPayBill(final ParkwellPayBillVo parkwellPayBillVo,
			CarParkOut carParkOut) throws BaseException
	{
		
		try
		{
			// 删除非当日滚动流水信息,2016-6-9
			paybillService.delRepaetBillNotInDay(parkwellPayBillVo);
			// 如果可以出场，则查询已支付的流水记录，且添加到历史
			List<LocalPayBillCopy> payBillLs = localPayBillCopyMapper
					.queryListByCarInUuid(parkwellPayBillVo.getCarInUuid());
			if (!Tools.isEmpty(payBillLs) && payBillLs.size() != 0)
			{
				List<LocalPayBill> list = new ArrayList<LocalPayBill>();
				for (LocalPayBillCopy pp : payBillLs)
				{
					LocalPayBill pb = new LocalPayBill();
					BeanUtil.copyProperties(pb, pp);
					
					pb.setPayBillUuid(UUIDGenerateUtil.generate());
					
					pb.setCarinCreatAt(!Tools.isEmpty(parkwellPayBillVo
							.getCarInTime()) ? parkwellPayBillVo.getCarInTime()
							: new Date());
					pb.setCaroutCareteAt(!Tools.isEmpty(parkwellPayBillVo
							.getCarOutTime()) ? parkwellPayBillVo
							.getCarOutTime() : new Date());
					pb.setStayTimeLong(DateUtil.betweenTimeString(
							parkwellPayBillVo.getCarOutTime(),
							parkwellPayBillVo.getCarInTime()));
					pb.setUserId(parkwellPayBillVo.getUserUuid());
					pb.setUserName(parkwellPayBillVo.getUserName());
					pb.setCarOutUuid(!Tools.isEmpty(carParkOut) ? carParkOut
							.getUuid() : null);
					paybillService.insertSelective(pb);
					
					Boolean repeat = RepeatStaticEntity.instance()
							.getRepeatStaticLock();
					// 如果开启了滚动计费
					if (!repeat)
					{
						// 流水运行表pay_bill_copy（微信支付，抵用券扣费） 生成流水表pay_bill
						LocalPayBillRepeat lbp = new LocalPayBillRepeat();
						BeanUtil.copyProperties(lbp, pb);
						localPayBillRepeatMapper.insertSelective(lbp);
					}
					list.add(pb);
				}
				parkwellPayBillVo.setCouponToPayBillsList(list);
			}
			
			/*
			 * //如果可以出场，更新最后一条流水，出场时间 LocalPayBill pb =
			 * paybillService.queryLastBill(parkwellPayBillVo.getCarInUuid());
			 * if (!Tools.isEmpty(pb)) {
			 * pb.setCarinCreatAt(!Tools.isEmpty(parkwellPayBillVo
			 * .getCarInTime()) ? parkwellPayBillVo.getCarInTime(): new Date());
			 * pb
			 * .setCaroutCareteAt(!Tools.isEmpty(parkwellPayBillVo.getCarOutTime
			 * ()) ? parkwellPayBillVo.getCarOutTime() : new Date());
			 * pb.setStayTimeLong
			 * (DateUtil.betweenTimeString(parkwellPayBillVo.getCarOutTime
			 * (),parkwellPayBillVo.getCarInTime()));
			 * pb.setUserId(parkwellPayBillVo.getUserUuid());
			 * pb.setUserName(parkwellPayBillVo.getUserName());
			 * paybillService.updateByPrimaryKeySelective(pb); }
			 */
			// 打印流水
			if (parkwellPayBillVo.isNeedPrintPayBill())
			{
				// 判断相机传送过来的数据是否有路口信息，防止伪数据
				List<Crossing> crossList = crossinService
						.queryCrossingByEquimentNo(carParkOut.getEquipment());
				
				if (Tools.isEmpty(crossList) || crossList.isEmpty())
				{
					parkwellPayBillVo.setError(true);
					parkwellPayBillVo.setErrorMsg("出场闸机或相机故障，请先排除设备故障.");
					parkwellPayBillVo.setResult(false);
					return 1;
				}
				// 更新进出场纪录
				carParkOut.setCarInUuid(parkwellPayBillVo.getCarInUuid());
				/* carInAndOutService.addCarParkOutBill(carParkOut); */
				
				// 打印流水
				LocalPayBill parkwellPayBill = new LocalPayBill();
				parkwellPayBill.setParkInUuid(parkwellPayBillVo.getCarInUuid());
				parkwellPayBill.setAttr3(parkwellPayBillVo.getStationUuid());
				parkwellPayBill.setPayBillUuid(UUIDGenerateUtil.generate());
				parkwellPayBill.setCarNo(parkwellPayBillVo.getCarNo());
				parkwellPayBill
						.setPayTime(new Date(System.currentTimeMillis()));
				
				parkwellPayBill.setPrice(!Tools.isEmpty(parkwellPayBillVo
						.getTheoryPriceDb()) ? parkwellPayBillVo
						.getTheoryPriceDb() : 0);
				
				if (parkwellPayBillVo.getCarNoTye().equals("白名单"))
				{
					parkwellPayBill.setActualPrice(0d);
				} else
				{
					
					parkwellPayBill
							.setActualPrice(!Tools.isEmpty(parkwellPayBillVo
									.getPriceDifference()) ? parkwellPayBillVo
									.getPriceDifference() : 0);
				}
				
				// 如果没有指定支付类型则为自动开闸出场车辆,否则为收现金执行开闸
				if (Tools.isEmpty(parkwellPayBillVo.getPayType()))
				{
					parkwellPayBill.setPayType(PayTypeConstans.MONEY_TYPE);
				} else
				{
					parkwellPayBill.setPayType(parkwellPayBillVo.getPayType());
				}
				
				// 处理纸质优惠券
				if (!Tools.isEmpty(parkwellPayBillVo.getCoupon())
						&& parkwellPayBillVo.getCoupon() > 0)
				{
					LocalCoupon lcoupon = new LocalCoupon();
					lcoupon.setBillUuid(parkwellPayBill.getPayBillUuid());
					lcoupon.setCarNo(parkwellPayBillVo.getCarNo());
					lcoupon.setCouponPrice(parkwellPayBillVo.getCoupon()
							.doubleValue());
					lcoupon.setCouponUuid(UUIDGenerateUtil.generate());
					lcoupon.setPayTime(new Date(System.currentTimeMillis()));
					lcoupon.setUserId(parkwellPayBillVo.getUserUuid());
					lcoupon.setUserName(parkwellPayBillVo.getUserName());
					localCouponService.insertSelective(lcoupon);
					
					// 2015-11-20 防止线程死锁。
					parkwellPayBillVo.setLcoupon(lcoupon);
					
					// 流水实际支付减去纸质优惠券金额
					// 挪到页面处理 2016-05-10
					// Double payNmub = parkwellPayBillVo.getPriceDifference();
					// if (!Tools.isEmpty(payNmub)
					// && payNmub - parkwellPayBillVo.getCoupon() > 0)
					// {
					// parkwellPayBill.setActualPrice(payNmub
					// - parkwellPayBillVo.getCoupon());
					// }
				}
				
				if (Tools.isEmpty(parkwellPayBill.getActualPrice())
						|| parkwellPayBill.getActualPrice() < 0)
				{
					parkwellPayBill.setActualPrice(0d);
				}
				
				// 如是自动扣费
				if (parkwellPayBillVo.isAuotPayOut())
				{
					Integration ingra = integrationService
							.queryInterationByCarNo(parkwellPayBillVo
									.getCarNo());
					ingra.setLessPrice(ingra.getLessPrice()
							- parkwellPayBillVo.getPriceDifference());
					integrationService.updateByPrimaryKeySelective(ingra);
					parkwellPayBill.setActualPrice(parkwellPayBillVo
							.getPriceDifference());
				}
				
				// 2015-12-10 添加进场出场信息
				parkwellPayBill.setCarOutUuid(carParkOut.getUuid());
				parkwellPayBill.setCaroutCareteAt(carParkOut.getCreateTime());
				parkwellPayBill.setCarinCreatAt(parkwellPayBillVo
						.getCarInTime());
				if (!Tools.isEmpty(parkwellPayBill.getCarinCreatAt())
						&& !Tools.isEmpty(parkwellPayBill.getCaroutCareteAt()))
				{
					// 停车时长
					String stayTimeLong = MyDateUtil.betweenTimeString(
							parkwellPayBill.getCaroutCareteAt(),
							parkwellPayBill.getCarinCreatAt());
					parkwellPayBill.setStayTimeLong(stayTimeLong);
				}
				// 2015-12-10 end
				
				parkwellPayBill.setUserId(parkwellPayBillVo.getUserUuid());
				parkwellPayBill.setUserName(parkwellPayBillVo.getUserName());
				parkwellPayBillMapper.insertSelective(parkwellPayBill);
				
				parkwellPayBillVo.setPayBill(parkwellPayBill);
				
				Boolean repeat = RepeatStaticEntity.instance()
						.getRepeatStaticLock();
				// 如果开启了滚动计费
				if (!repeat)
				{
					// 流水运行表pay_bill_copy（微信支付，抵用券扣费） 生成流水表pay_bill
					LocalPayBillRepeat lbp = new LocalPayBillRepeat();
					BeanUtil.copyProperties(lbp, parkwellPayBill);
					localPayBillRepeatMapper.insertSelective(lbp);
				}
			}
		} catch (Exception e)
		{
			e.printStackTrace();
			throw new BaseException(e.getMessage());
		}
		
		// TODO need test
		ThreadPoolUtil.instance().execute(new Runnable()
		{
			@Override
			public void run()
			{
				String carInUuid = parkwellPayBillVo.getCarInUuid();
				if (!StringUtils.isEmpty(carInUuid))
				{
					CarParkInCopy carInCopy = carParkInCopyMapper
							.selectByPrimaryKey(carInUuid);
					if (null != carInCopy)
					{
						Map<FieldEnum, Object> map = new HashMap<FieldEnum, Object>();
						map.put(FieldEnum.CONTENTS, carInCopy.getCarNo());
						map.put(FieldEnum.MODIFY_TIME, String.valueOf(carInCopy
								.getCreateTime().getTime()));
						map.put(FieldEnum.STRING_FIELD, carInUuid);

						IndexWriter writer = IndexUtil.getIndexWriter(LuceneConstants.ROOT_PATH
								+ CarParkInCopy.class.getSimpleName(), true);
						IndexUtil.indexDoc(writer, Arrays.asList(map));
						IndexUtil.closeWriter();
					}
				}
				
				String carOutUuid = parkwellPayBillVo.getCarOutUuid();
				if (!StringUtils.isEmpty(carOutUuid))
				{
					CarParkOutCopy carOutCopy = carParkOutCopyMapper
							.selectByPrimaryKey(carOutUuid);
					if (null != carOutCopy)
					{
						Map<FieldEnum, Object> map = new HashMap<FieldEnum, Object>();
						map.put(FieldEnum.CONTENTS, carOutCopy.getCarNo());
						map.put(FieldEnum.MODIFY_TIME, String
								.valueOf(carOutCopy.getCreateTime().getTime()));
						map.put(FieldEnum.STRING_FIELD, carOutUuid);

						IndexWriter writer = IndexUtil.getIndexWriter(LuceneConstants.ROOT_PATH
								+ CarParkOutCopy.class.getSimpleName(),
								true);
						IndexUtil.indexDoc(writer, Arrays.asList(map));
						IndexUtil.closeWriter();
					}
				}
				
				String billUuid = parkwellPayBillVo.getUuid();
				if (!StringUtils.isEmpty(billUuid))
				{
					LocalPayBill localPayBill = parkwellPayBillMapper
							.selectByPrimaryKey(billUuid);
					if (null != localPayBill)
					{
						Map<FieldEnum, Object> map = new HashMap<FieldEnum, Object>();
						map.put(FieldEnum.CONTENTS, localPayBill.getCarNo());
						map.put(FieldEnum.STRING_FIELD, billUuid);

						IndexWriter writer = IndexUtil.getIndexWriter(LuceneConstants.ROOT_PATH
								+ LocalPayBillRepeat.class.getSimpleName(),
								true);
						IndexUtil.indexDoc(writer, Arrays.asList(map));
						IndexUtil.closeWriter();
					}
				}
			}
		});
		return 1;
	}
	
	@Override
	public Integer updataForCarOut(String carOutUUid, String carInUUid)
			throws BaseException
	{
		try
		{
			CarParkOut carOutInfo = carParkOutMapper
					.selectByPrimaryKey(carOutUUid);
			if (Tools.isEmpty(carOutInfo))
			{
				return -1;
			}
			
			CarParkIn carInInfo = carParkInMapper.selectByPrimaryKey(carInUUid);
			if (!Tools.isEmpty(carInInfo))
			{
				
				if (!Tools.isEmpty(carInInfo.getStatus())
						&& carInInfo.getStatus() != 0)
				{
					
					carInInfo.setStatus(0);
					carParkInMapper.updateByPrimaryKeySelective(carInInfo);
				}
				
			}
			
			// 更新出场纪录
			if (!Tools.isEmpty(carOutInfo.getStatus())
					&& carOutInfo.getStatus() != 0)
			{
				carOutInfo.setStatus(0);// 正常出场
				carOutInfo.setCarInUuid(carInUUid);
				carParkOutMapper.updateByPrimaryKeySelective(carOutInfo);
			}
			
			// 推送总车位数
			PushParkLotRunble lotRunbile = new PushParkLotRunble(
					carParkInMapper, lotNumberMapper);
			ThreadPoolUtil.instance().execute(lotRunbile);
			
			// 进场
			if (CloudConfigManager.instance().isOpen()
					&& carInInfo.getStatus() == 0)
			{
				UploadCarInInfoRunble upload = new UploadCarInInfoRunble(
						carInInfo, logService);
				ThreadPoolUtil.instance().execute(upload);
			}
			
			// 出场
			if (CloudConfigManager.instance().isOpen())
			{
				UpDateCarOutInfoRunble upload = new UpDateCarOutInfoRunble(
						carOutInfo, logService);
				ThreadPoolUtil.instance().execute(upload);
			}
			
		} catch (Throwable e)
		{
			throw new BaseException(e.getMessage());
		}
		return 0;
	}
	
	@Override
	public Integer copyToOhterTable(String carOutUUid, String carInUUid)
			throws BaseException
	{
		
		// 推送总车位数
		PushParkLotRunble lotRunbile = new PushParkLotRunble(carParkInMapper,
				lotNumberMapper);
		ThreadPoolUtil.instance().execute(lotRunbile);
		
		// 去除更新到云的 进场，，云出场的时候，自动更新进出场
		/*
		 * CarParkIn carInInfo = carParkInMapper.selectByPrimaryKey(carInUUid);
		 * if (!Tools.isEmpty(carInInfo)) { // 进场 if
		 * (CloudConfigManager.instance().isOpen() && carInInfo.getStatus() ==
		 * 0) { UploadCarInInfoRunble upload = new UploadCarInInfoRunble(
		 * carInInfo, logService); ThreadPoolUtil.instance().execute(upload); }
		 * }
		 */
		
		CarParkOut carOutInfo = carParkOutMapper.selectByPrimaryKey(carOutUUid);
		
		// 2015-12-10 更新出场纪录下的进场纪录信息,为了保险起见放到finally执行
		if (!Tools.isEmpty(carInUUid))
		{
			// 出场后,删除计费规则副本
			LocalChargeBytimeCopyExample ex = new LocalChargeBytimeCopyExample();
			ex.or().andCarInUuidEqualTo(carInUUid);
			chargeBytimeMapper.deleteByCondition(ex);
			
			carOutInfo.setCarInUuid(carInUUid);
			CarParkIn carIn = carParkInMapper.selectByPrimaryKey(carInUUid);
			if (!Tools.isEmpty(carIn))
			{
				carIn.setStatus(0);
				CarParkInCopy carParkInCopy = new CarParkInCopy();
				BeanUtil.copyProperties(carParkInCopy, carIn);
				carParkInCopyMapper.insertSelective(carParkInCopy);
				carParkInMapper.deleteByPrimaryKey(carInUUid);
			}
		}
		// 2015-12-10 end
		
		// 添加出场副本表
		CarParkOutCopy carParkOutCopy = new CarParkOutCopy();
		carOutInfo.setStatus(0);
		BeanUtil.copyProperties(carParkOutCopy, carOutInfo);
		if (!Tools.isEmpty(carParkOutCopy))
		{
			carParkOutCopyMapper.insertSelective(carParkOutCopy);
			carParkOutMapper.deleteByPrimaryKey(carOutInfo.getUuid());
		}
		return 1;
	}
	
	@Override
	public void returnCashOrVouchers(ParkwellPayBillVo parkwellPayBillVo,
			String carInUuid)
	{
		// TODO Auto-generated method stub
		LocalPayBillCopyExample condition = new LocalPayBillCopyExample();
		condition.or().andParkInUuidEqualTo(carInUuid);
		List<LocalPayBillCopy> listbillList = parkwellPayBillCopyMapper
				.queryListByCarInUuid(carInUuid);
		if (!Tools.isEmpty(listbillList) && listbillList.size() > 0)
		{
			double couponCashPrice = 0d;
			double couponVouchers = 0d;
			for (LocalPayBillCopy lb : listbillList)
			{
				if (!Tools.isEmpty(lb.getPayType())
						&& lb.getPayType().equalsIgnoreCase("抵用劵"))
				{
					couponCashPrice += lb.getPrice();
				}
				if (!Tools.isEmpty(lb.getPayType())
						&& lb.getPayType().equalsIgnoreCase("代金劵"))
				{
					couponVouchers += lb.getPrice();
				}
			}
			parkwellPayBillVo.setCouponCashPrice(couponCashPrice);
			parkwellPayBillVo.setCouponVouchers(couponVouchers);
		}
	}
	
	@Override
	public AdminPayBill manualOpenCarOut(ParkwellPayBillVo parkwellPayBillVo)
			throws BaseException
	{
		try
		{
			CarParkOut carParkOut = carParkOutMapper
					.selectByPrimaryKey(parkwellPayBillVo.getCarOutUuid());
			
			if (Tools.isEmpty(carParkOut))
			{
				throw new BaseException("50000-00001-00064");
			}
			
			if (!Tools.isEmpty(parkwellPayBillVo.getCarNo()))
			{
				carParkOut.setCarNo(parkwellPayBillVo.getCarNo());
			}
			
			carParkOut.setOpenMode(GateWayConstans.MANUAL);
			carParkOut.setBrand(parkwellPayBillVo.getBillType());
			carParkOut.setStatus(0);
			// carParkOutMapper.updateByPrimaryKeySelective(carParkOut);
			CarParkOutCopy carParkOutCopy = new CarParkOutCopy();
			BeanUtil.copyProperties(carParkOutCopy, carParkOut);
			carParkOutMapper.deleteByPrimaryKey(carParkOut.getUuid());
			carParkOutCopyMapper.insertSelective(carParkOutCopy);// 拷贝到副本表
			
			// 添加强制开闸
			AdminPayBill adminPayBill = new AdminPayBill();
			adminPayBill.setLonginUserUuid(parkwellPayBillVo.getUserUuid());
			adminPayBill.setCarNo(carParkOut.getCarNo());
			adminPayBill.setStationUuid(parkwellPayBillVo.getStationUuid());
			adminPayBill.setCrossingId(parkwellPayBillVo.getRoadUuid());
			/*
			 * Map<String, Object> map = carInAndOutService
			 * .getIdentityTypeByCarNo(carParkOut.getCarNo()); String carNoType
			 * = (String) map.get("carNoType");
			 */
			adminPayBill.setRemar(!Tools.isEmpty(parkwellPayBillVo
					.getCarNoTye()) ? parkwellPayBillVo.getCarNoTye()
					: MessageContains.TEMP_CAR_TYPE);
			adminPayBillService.addAdminPayBill(adminPayBill);
			Screen screen = localScreenMapper
					.queryScreenByCamelDeviceId(carParkOut.getEquipment());
			parkwellPayBillVo.setScreen(screen);
			return adminPayBill;
		} catch (Throwable t)
		{
			log.error(t.getMessage(), t);
			throw new BaseException(t.getMessage());
		}
		
	}
	
	@Override
	public void carOutNew(ParkwellPayBillVo parkwellPayBillVo,
			CarParkOut carParkOut) throws BaseException
	{
		try
		{
			
			// 填充岗亭信息
			// 添加出口岗亭信息 2016-8-10
			List<Crossing> crossList = crossinService
					.queryCrossingByEquimentNo(carParkOut.getEquipment());
			
			if (!crossList.isEmpty())
			{
				LocalStation staion = crossinService
						.findStationByCrosId(crossList.get(0).getUuid());
				if (!Tools.isEmpty(staion))
				{
					carParkOut.setStationUuid(staion.getStationUuid());
				}
			}
			// 添加出口岗亭信息 2016-8-10
			
			if (Tools.isEmpty(parkwellPayBillVo.getScreen()))
			{
				Screen screen = localScreenMapper
						.queryScreenByCamelDeviceId(carParkOut.getEquipment());
				parkwellPayBillVo.setScreen(screen);
			}
			carParkOut.setStatus(0);
			if (Tools.isEmpty(carParkOutCopyMapper
					.selectByPrimaryKey(carParkOut.getUuid())))
			{
				CarParkOutCopy carParkOutCopy = new CarParkOutCopy();
				BeanUtil.copyProperties(carParkOutCopy, carParkOut);
				carParkOutCopy.setCarInUuid(parkwellPayBillVo.getCarInUuid());
				carParkOutCopyMapper.insertSelective(carParkOutCopy); // 插入出场副本表
			}
			
			// 移除进场仓库表数据
			if (!Tools.isEmpty(parkwellPayBillVo.getRepertoryUuid()))
			{
				localCarInRepertoryMapper.deleteByPrimaryKey(parkwellPayBillVo
						.getRepertoryUuid());
				
			} else if (!Tools.isEmpty(parkwellPayBillVo.getCarInUuid()))
			{
				// 移除进场仓库信息,通过进场uuid移除
				LocalCarInRepertoryExample carInEx = new LocalCarInRepertoryExample();
				carInEx.or().andCarInUuidEqualTo(
						parkwellPayBillVo.getCarInUuid());
				/* carInEx.or().andCarNoEqualTo(carParkOut.getCarNo().trim()); */
				List<LocalCarInRepertory> localCarInRepertories = localCarInRepertoryMapper
						.selectByCondition(carInEx);
				if (!Tools.isEmpty(localCarInRepertories))
				{
					for (LocalCarInRepertory carInRepertory : localCarInRepertories)
					{
						if (!Tools.isEmpty(carInRepertory))
						{
							localCarInRepertoryMapper
									.deleteByPrimaryKey(carInRepertory
											.getUuid());
						}
					}
				}
			} else if (!Tools.isEmpty(parkwellPayBillVo.getCarNo())) // 通过车牌移除
			{
				// 移除进场仓库信息,通过进场uuid移除
				LocalCarInRepertoryExample carInEx = new LocalCarInRepertoryExample();
				carInEx.or().andCarNoEqualTo(parkwellPayBillVo.getCarNo());
				/* carInEx.or().andCarNoEqualTo(carParkOut.getCarNo().trim()); */
				List<LocalCarInRepertory> localCarInRepertories = localCarInRepertoryMapper
						.selectByCondition(carInEx);
				if (!Tools.isEmpty(localCarInRepertories))
				{
					for (LocalCarInRepertory carInRepertory : localCarInRepertories)
					{
						if (!Tools.isEmpty(carInRepertory))
						{
							localCarInRepertoryMapper
									.deleteByPrimaryKey(carInRepertory
											.getUuid());
						}
					}
				}
			}// end 移除仓库表
			
			// 删除进场纪录、并拷贝到副本表、删除进场计费副本
			if (!Tools.isEmpty(parkwellPayBillVo.getCarInUuid()))
			{
				CarParkIn carInInfo = carParkInMapper
						.selectByPrimaryKey(parkwellPayBillVo.getCarInUuid());
				if (Tools.isEmpty(carInInfo))
				{
					carInInfo = carParkInMapper
							.queryMaxInByCarNo(parkwellPayBillVo.getCarNo());
				}
				if (!Tools.isEmpty(carInInfo))
				{
					// 拷贝进场纪录到进场副本，并删除进场纪录
					CarParkInCopy carParkInCopy = new CarParkInCopy();
					BeanUtil.copyProperties(carParkInCopy, carInInfo);
					carParkInCopy.setStatus(0);
					carParkInCopyMapper.insertSelective(carParkInCopy);
					carParkInMapper.deleteByPrimaryKey(carInInfo.getUuid());
				}
				
			}// end if
			
			if (!Tools.isEmpty(carParkOut)
					&& !Tools.isEmpty(carParkOut.getUuid()))
			{
				carParkOutMapper.deleteByPrimaryKey(carParkOut.getUuid());
			}
			// 打印流水信息
			createPayBill(parkwellPayBillVo, carParkOut);
			
			// 删除流水副本信息
			deletePayBillCopy(parkwellPayBillVo);
			
			// 上报至云平台，百事通平台等，一些列平台
			// uploadPlatform(parkwellPayBillVo, carParkOut,logService);
			
		} catch (Throwable t)
		{
			log.error("ParkwellCarOutServiceImpl", t);
			throw new BaseException(t.getMessage());
		}
	}
	
	public void uploadPlatform(ParkwellPayBillVo parkwellPayBillVo,
			CarParkOut carParkOut, LogService logService)
	{
		UploadPlatformThread platForm = new UploadPlatformThread(carParkOut,
				logService, parkwellPayBillVo);
		ThreadPoolUtil.instance().execute(platForm);
	}
	
	@Override
	public Integer deletePayBillCopy(ParkwellPayBillVo payBillVo)
			throws BaseException
	{
		// TODO Auto-generated method stub
		if (!Tools.isEmpty(payBillVo)
				&& !Tools.isEmpty(payBillVo.getCarInUuid()))
		{
			LocalPayBillCopyExample condtion = new LocalPayBillCopyExample();
			condtion.or().andParkInUuidEqualTo(payBillVo.getCarInUuid());
			localPayBillCopyMapper.deleteByCondition(condtion);
			return 1;
		}
		return 0;
		
	}
	
	/**
	 * 
	 * 方法描述： 临时车计费后小于等于0时，分装数据结构
	 * 
	 * @Title: encapsulationPayBill
	 * @param @param parkwellPayBillVo
	 * @param @param carParkOut
	 * @param @param ltc
	 * @param @param screenMessage
	 * @return void
	 * @user liyf 2016年6月9日
	 * @throws
	 */
	private void encapsulationPayBill(ParkwellPayBillVo parkwellPayBillVo,
			CarParkOut carParkOut, LocalChargeBytimeType ltc,
			ScreenMessage screenMessage)
	{
		carParkOut.setAttr1(parkwellPayBillVo.getCarNoTye());
		carParkOut
				.setCarType(Tools.isEmpty(parkwellPayBillVo.getCarTypeUuid()) ? parkwellPayBillVo
						.getCarTypeUuid() : ConfigManager.instance()
						.getDefaultCarType());
		parkwellPayBillVo.setPayStatus(CommonContains.PAY_TYPE_TRUE);
		parkwellPayBillVo.setResult(true);
		parkwellPayBillVo.setNeedPrintPayBill(true);
		parkwellPayBillVo.setCarNoTye(!Tools.isEmpty(ltc) ? ltc.getName()
				: "临时车");
		parkwellPayBillVo.setBillType(!Tools.isEmpty(ltc) ? ltc.getType()
				: "102");
		
		screenMessage.setHeadMsg(parkwellPayBillVo.getCarNo());
		screenMessage.setSecMsg(ltc.getName());
		screenMessage.setThirdMsg(MessageContains.GOOD_BYE_MSG);
		
		carParkOut.setBrand(!Tools.isEmpty(ltc) ? ltc.getType() : "102");
		parkwellPayBillVo.setScreenMsg(screenMessage);
	}
	
}
